package com.kd.crawler.common.utils;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.PatternSyntaxException;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import com.kd.crawler.common.exception.XMLParserException;


/**
 * 
* @类名: XmlParser 
* @类功能描述: 解析xml
* @时间 ：2011-4-13 上午08:33:50
 */
public class XMLParser {
	
	/**
	 * cache xml
	 * @param xmlPath
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static Map<String, Element> cacheXml(String xmlPath) {
		if(null==xmlPath || "".equals(xmlPath)) {
			return null;
		}
		
		File f = new File(XMLParser.class.getClassLoader().getResource(xmlPath).getPath());
		if(!f.exists()) {
			return null;
		}
		
		try {
			Map<String, Element> map = new HashMap<String, Element>();
			SAXReader reader = new SAXReader(); 
			Document doc = reader.read(f);
			Element root = doc.getRootElement();
			Iterator<Element> iter = root.elementIterator();
			while(iter.hasNext()) {
				Element node = iter.next();
				map.put(node.attributeValue("domain"), node);
			}
			return map;
		} catch (DocumentException e) {
			e.printStackTrace();
			return null;
		}
	}
	
	/**
	 * according to node name, get its node element from document root node.
	 * @param doc
	 * @param nodeName
	 * @return
	 */
	public static Element getElement(Document doc, String nodeName) {
		if(null == doc) {
			return null;
		}
		if(null==nodeName || "".equals(nodeName)) {
			return null;
		}
		
		Element root = doc.getRootElement();
		@SuppressWarnings("unchecked")
		Iterator<Element> iter = root.elementIterator();
		while(iter.hasNext()) {
			Element node = iter.next();
			if(nodeName.equals(node.getName())) {
				return node;
			}
		}
		return null;
	}
	
	/**
	 * get all of texts below xPath from the document.
	 * @param doc
	 * @param xPath, format: title.jsoup, it represents that the method will return text array, otherwise it is invalid and return null.
	 * @return
	 */
	public static List<String> getMoreText(Document doc, String xPath) {
		if(null == doc) {
			return null;
		}
		if(null==xPath || "".equals(xPath)) {
			return null;
		}
		
		List<String> texts = new ArrayList<String>();
		
		String[] nodeNames = null;
		try {
			nodeNames = xPath.split("\\.");
			if(2!=nodeNames.length || null==nodeNames[0] || "".equals(nodeNames[0]) || null==nodeNames[1] || "".equals(nodeNames[1])) {
				throw new XMLParserException("the xPath format is invalid, such like title.jsoup to return jsoup array text");
			}
		} catch (PatternSyntaxException e) {
			e.printStackTrace();
			return null;
		} catch (XMLParserException e) {
			e.printStackTrace();
			return null;
		}
		Element domainsNode = getElement(doc, nodeNames[0]);
		@SuppressWarnings("unchecked")
		List<Element> elements = domainsNode.elements();
		for(Element e : elements) {
			if(nodeNames[1].equals(e.getName())) {
				String text = e.getTextTrim();
				if(null==text || "".equals(text)) {
					continue;
				}
				texts.add(e.getTextTrim());
			}
		}
		return texts;
	}
	public static List<String> getMoreText(String path, String xPath) {
		return getMoreText(getDocument(path), xPath);
	}
	
	public static List<Element> getChildrenElements(String path, String xPath){
		Document doc=getDocument(path);
		return getChildrenElements(doc,xPath);
	}
	
	public static List<Element> getChildrenElements(Document doc, String xPath){
		Element element = doc.getRootElement();
		if(xPath==null||xPath.trim().equals("")){
			return element.elements();
		}
		String elementNames[]=xPath.split("\\.");
		for(int i=0;i<elementNames.length;i++){
			element=element.element(elementNames[i]);
		}		
		return element.elements();
	}
	
	/**
	 * get back document by the path
	 * @param path: it must be absolute path
	 * @return
	 */
	public static Document getDocument(String path) {
		if(null==path || "".equals(path)) {
			return null;
		}
		Document doc = null;
		try {
			SAXReader reader = new SAXReader(); 
			doc = reader.read(path);
		} catch (DocumentException e) {
			e.printStackTrace();
		}
		return doc;
	}

	/**
	 * get all of domains from the file path
	 * @param doc
	 * @return
	 */
	public static List<String> getDamains(String path) {
		return getDomains(getDocument(path));
	}
	/**
	 * get all of domains from the given document
	 * @param doc
	 * @return
	 */
	public static List<String> getDomains(Document doc) {
		return getMoreText(doc, "domains.item");
	}
	
	/**
	 * here, maybe not perfect
	 * @param doc
	 * @return
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static Map<String, Object> Dom2Map(Document doc){
		Map<String, Object> map = new HashMap<String, Object>();
		if(doc == null)
			return map;
		Element root = doc.getRootElement();
		for (Iterator<Element> iterator = root.elementIterator(); iterator.hasNext();) {
			Element e = iterator.next();
			//System.out.println(e.getName());
			List list = e.elements();
			if(list.size() > 0){
				map.put(e.attributeValue("domain"), Dom2Map(e));
			} else
				map.put(e.getName(), e.getText());
		}
		return map;
	}
	

	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static Map<String, Object> Dom2Map(Element e){
		Map<String, Object>	map = new HashMap<String, Object>();
		List list = e.elements();
		if(list.size() > 0){
			for (int i = 0;i < list.size(); i++) {
				Element iter = (Element) list.get(i);
				List<Object> mapList = new ArrayList<Object>();
				
				if(iter.elements().size() > 0){
					Map<String, Object> m = Dom2Map(iter);
					if(map.get(iter.getName()) != null){
						Object obj = map.get(iter.getName());
						if(!obj.getClass().getName().equals("java.util.ArrayList")){
							mapList = new ArrayList<Object>();
							mapList.add(obj);
							mapList.add(m);
						}
						if(obj.getClass().getName().equals("java.util.ArrayList")){
							mapList = (List<Object>) obj;
							mapList.add(m);
						}
						map.put(iter.getName(), mapList);
					}else
						map.put(iter.getName(), m);
				}
				else{
					if(map.get(iter.getName()) != null){
						Object obj = map.get(iter.getName());
						if(!obj.getClass().getName().equals("java.util.ArrayList")){
							mapList = new ArrayList<Object>();
							mapList.add(obj);
							mapList.add(iter.getText());
						}
						if(obj.getClass().getName().equals("java.util.ArrayList")){
							mapList = (List<Object>) obj;
							mapList.add(iter.getText());
						}
						map.put(iter.getName(), mapList);
					}else
						map.put(iter.getName(), iter.getText());
				}
			}
		}else
			map.put(e.getName(), e.getText());
		return map;
	}
	

	public static void main(String[] args) {
		
		
		Document doc = XMLParser.getDocument(XMLParser.class.getClassLoader().getResource("_010lfNewsAnalyse.xml").getPath());
		List<Element> list=XMLParser.getChildrenElements(doc, "");
		for(Element item:list){
			System.out.println(item.getName());
		}
		
		
	}
	
}


